package cn.nexttec.noteplayer.ui.activities

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.content.res.Resources
import android.media.AudioManager
import android.media.MediaMetadataRetriever
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.provider.Settings
import android.util.Log
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
import android.view.ViewConfiguration
import android.view.WindowManager
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.transition.TransitionManager
import cn.nexttec.noteplayer.R
import cn.nexttec.noteplayer.common.BR
import cn.nexttec.noteplayer.common.EYE
import cn.nexttec.noteplayer.common.FloatingToolbar
import cn.nexttec.noteplayer.common.GazeTrackingController
import cn.nexttec.noteplayer.common.Preference
import cn.nexttec.noteplayer.common.SCROLL
import cn.nexttec.noteplayer.common.VOL
import cn.nexttec.noteplayer.common.copyFile
import cn.nexttec.noteplayer.common.debug
import cn.nexttec.noteplayer.common.formatMillsecond
import cn.nexttec.noteplayer.common.formatPosition
import cn.nexttec.noteplayer.common.gson
import cn.nexttec.noteplayer.databinding.ActivityPlayerBinding
import cn.nexttec.noteplayer.models.EyeReport
import cn.nexttec.noteplayer.models.NoteFile
import cn.nexttec.noteplayer.models.SubtitleOption
import cn.nexttec.noteplayer.models.TrackSelectionOption
import cn.nexttec.noteplayer.models.VideoFileInfo
import cn.nexttec.noteplayer.service.TraceService
import cn.nexttec.noteplayer.ui.widget.PopupDialog
import cn.nexttec.noteplayer.viewmodels.PlayViewModel
import com.bumptech.glide.Glide
import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.source.MergingMediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.source.SingleSampleMediaSource
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
import com.google.android.exoplayer2.ui.DefaultTimeBar
import com.google.android.exoplayer2.ui.TimeBar
import com.google.android.exoplayer2.upstream.DefaultDataSource
import com.google.android.exoplayer2.util.MimeTypes
import com.google.android.exoplayer2.video.VideoSize
import dagger.hilt.android.AndroidEntryPoint
import java.io.File
import javax.inject.Inject
import javax.inject.Named
import kotlin.math.abs
import kotlin.math.sqrt


@AndroidEntryPoint
class PlayerActivity : AppCompatActivity(), ScaleGestureDetector.OnScaleGestureListener {


    @Inject
    @Named("BaseDir")
    lateinit var noteDir: File
    private var conn: ServiceConnection? = null
    private var noteFile: NoteFile? = null
    private var soundTracks: List<TrackSelectionOption>? = null
    private var subtitleOptions: List<SubtitleOption>? = null
    private lateinit var scaleGestureDetector: ScaleGestureDetector
    private var gazeTrackingController: GazeTrackingController? = null
    private var isPaused: Boolean = false
    private lateinit var gestureDetector: GestureDetector
    private var isScrolling = false
    private var realScreenWidth: Int = 0
    private var realScreenHeight: Int = 0
    private var initialTouchTime = 0L
    private var touchSlop: Int = 0
    private var isRecording = false
    private var recordStartPos = 0L

    @Inject
    lateinit var preference: Preference

    private val viewModel: PlayViewModel by viewModels()
    private var videos: List<VideoFileInfo>? = null
    private var scrollDirection = ScrollDirection.NONE
    private val handler = Handler(Looper.getMainLooper())
    private lateinit var exoPlayer: ExoPlayer
    private lateinit var trackSelector: DefaultTrackSelector
    private var subtitleFilename: String? = ""
    private var isLandscape = false
    private var isShowNoteContainer = false
    private var preIsShowNoteContainer = false
    private lateinit var _binding: ActivityPlayerBinding
    private val binding: ActivityPlayerBinding get() = _binding
    private lateinit var btnNote: ImageView
    private lateinit var btnSpeed: ImageView
    private lateinit var btnAudio: ImageView
    private lateinit var btnLock: ImageView
    private lateinit var btnPlayList: ImageView
    private lateinit var btnSubtitle: ImageView
    private lateinit var btnResize: ImageView
    private lateinit var btnBack: ImageView
    private lateinit var btnRotate: ImageView
    private lateinit var timeBar: DefaultTimeBar
    private lateinit var titleView: TextView
    private lateinit var btnZoom: ImageView
    private lateinit var btnSoundTrackSelector: ImageView
    private lateinit var btnSubtitleSelector: ImageView
    private lateinit var endContainer: RelativeLayout
    private lateinit var btnReplay: ImageView
    private lateinit var btnPreVideo: RelativeLayout
    private lateinit var btnNextVideo: RelativeLayout
    private lateinit var ivPreVideo: ImageView
    private lateinit var ivNextVideo: ImageView
    private lateinit var tvPreVideo: TextView
    private lateinit var tvNextVideo: TextView
    private var selectedSoundTrack = 0
    private lateinit var notePanel: FloatingToolbar
    private lateinit var traceService: TraceService

    private var lastDragX = 0f
    private var lastDragY = 0f
    private var translateX = 0f
    private var translateY = 0f
    private var accumulatedX = 0f
    private var accumulatedY = 0f
    private val adjustmentThreshold = 30f  // 可调节阈值（像素）

    private var lastPosition: Long = 0L
    private var portraitVideoContainerHeight = 0
    private var selectedSpeed: Float = 1f
    private var hasSubtitle: Boolean = false
    private var isFirstReady: Boolean = false

    private var isLocked: Boolean = false
    private var videoInfo: VideoFileInfo? = null
    private var videoSize: Pair<Int, Int>? = null // 预先获取的分辨率

    private var initialTouchDistance = 0f
    private var initialScale = 1f
    private var currentScale = 1f
    private val minScale = 1.0f
    private val maxScale = 3.0f
    private var videoAspectRatio = 16f / 9f // 默认16:9，实际值从视频中获取
    private var hasEyeOn = false
    private var preHasEyeOn = false
    private var screenWidth = 0
    private var screenHeight = 0
    private var initialX = 0f
    private var initialY = 0f
    private var isLeftSide = false
    private var resizeMode = 1
    private var showSubtitle = true
    private var isZoomMode = false
    private var pivotX = 0f
    private var pivotY = 0f
    private lateinit var screenShotLauncher: ActivityResultLauncher<Intent>

    lateinit var mediaDir: File


    private val wakeRunnable = object : Runnable {
        override fun run() {
            // 重新请求常亮，防止系统省电机制降低亮度
            window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
            handler.postDelayed(this, 10_000) // 每 30 秒执行一次
        }
    }

    companion object {
        private const val TAG = "PlayerActivity"
        private const val REQUEST_CODE_PICK_SUBTITLE = 9001
        fun start(context: Context, videoFileInfo: VideoFileInfo, position:Long = 0) {
            val intent = Intent(context, PlayerActivity::class.java)
            intent.putExtra(TAG, videoFileInfo)
            intent.putExtra("POSITION", position)
            context.startActivity(intent)
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.decorView.systemUiVisibility =
            View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
        supportActionBar?.hide()
        _binding = ActivityPlayerBinding.inflate(layoutInflater)
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)

        conn = TraceService.bindService(this@PlayerActivity, onConnected = {
            this.traceService = it
        })
        setContentView(binding.root)

        trackSelector = DefaultTrackSelector(this@PlayerActivity)
        trackSelector.parameters = trackSelector.buildUponParameters()
            .setPreferredTextLanguage("zh") // 可设置默认语言
            .build()

        exoPlayer = ExoPlayer.Builder(this@PlayerActivity).build()
        // 沉浸式状态栏代码省略，保持你原来的
        getRealScreenSize()

        // 获取视频信息
        videoInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            intent.getSerializableExtra(TAG, VideoFileInfo::class.java)
        } else {
            intent.getSerializableExtra(TAG) as VideoFileInfo
        }
        lastPosition= intent.getLongExtra("POSITION", 0L)

        viewModel.playPosition.observe(this) {
            lastPosition = it
            TAG debug "PlayerActivity:lastPosition:$lastPosition"
            runOnUiThread {
                if (lastPosition > 0L) {
                    exoPlayer.seekTo(lastPosition)
                    binding.tvProgress.visibility = View.VISIBLE
                    binding.tvProgress.text = lastPosition.formatMillsecond()
                    handler.postDelayed({ binding.tvProgress.visibility = View.GONE }, 2000L)
                }
            }
        }

        viewModel.cropResult.observe(this) {
            if (it is PlayViewModel.RecordResult.Success) {
                exoPlayer.pause()
                notePanel.hide()
                PopupDialog.showVideoCropDialog(
                    videoInfo!!,
                    it.startPos,
                    it.endPos,
                    onCrop = { name ->
                        TAG debug "Done"
                        notePanel.show()
                        exoPlayer.play()
                        addVideo(File(it.videoPath), name)
                    },
                    onCancel = {})

            }
            if (it is PlayViewModel.RecordResult.Fail) {
                PopupDialog.showAlertDialog(it.message, onConfirm = {}, onCancel = {})
            }
        }

        viewModel.screenShotResult.observe(this) {
            if (it is PlayViewModel.ScreenShotResult.Favorite) {
                PopupDialog.addFavorite(
                    it.imagePath,
                    exoPlayer.currentPosition,
                    onSave = { name, pos ->
                        val destFile = File(mediaDir, "${videoInfo!!.videoMd5}_pos_${pos}.jpg")
                        if(copyFile(File(it.imagePath), destFile)) {
                            val syntax =
                                "f{$name}[media/${destFile.name}](${videoInfo!!.videoMd5})<${pos}>"
                            writeToNoteTile(syntax)
                        }
                        exoPlayer.play()
                        notePanel.show()
                    },
                    onCancel = {
                        exoPlayer.play()
                        notePanel.show()
                    })
            }
            if (it is PlayViewModel.ScreenShotResult.Success) {
                PopupDialog.showScreenShotAlert(videoInfo!!, it.imagePath,
                    onEdit = { tempImagePath ->
                        val intent = Intent(this@PlayerActivity, ImageEditorActivity::class.java)
                        intent.putExtra("image", tempImagePath)
                        screenShotLauncher.launch(intent)
                    }, onConfirm = {
                        addImage(it)
                    }, onCancel = {
                        val file = File(it)
                        if (file.exists()) {
                            file.delete()
                        }
                        notePanel.show()
                        if (exoPlayer.isPlaying.not()) {
                            exoPlayer.play()
                        }
                    })
            }
        }

        initVideo()

        scaleGestureDetector = ScaleGestureDetector(this, this@PlayerActivity)
        touchSlop = ViewConfiguration.get(this).scaledTouchSlop * 2
        binding.playerView.post {
            initUi()
        }
        initEyeTrace()
        val pickImageLauncher = registerForActivityResult(
            ActivityResultContracts.GetContent()
        ) { uri: Uri? ->
            uri?.let { notePanel.insertImage(uri) }
        }

        notePanel = FloatingToolbar(this@PlayerActivity, pickImageLauncher, binding.container)
        notePanel.addListener(object : FloatingToolbar.ButtonClickedListener {
            override fun onVideoCropStart() {
                isRecording = true
                recordStartPos = exoPlayer.currentPosition
            }

            override fun onVideoFavorite() {
                exoPlayer.pause()
                notePanel.hide()
                viewModel.favorite(videoInfo!!, exoPlayer.currentPosition)

            }

            override fun onNoteClicked() {
                exoPlayer.pause()
                val intent = Intent(this@PlayerActivity, EditorActivity::class.java)
                intent.putExtra("note", noteFile)
                startActivity(intent)
            }

            override fun onScreenShot() {
                exoPlayer.pause()
                notePanel.hide()
                viewModel.screenshot(videoInfo!!, exoPlayer.currentPosition)

            }

            override fun onNoteSave(markdownText: String) {
                writeToNoteTile(markdownText)

            }

            override fun onVideoCropEnd(): Boolean {
                if (recordStartPos >= exoPlayer.currentPosition) {
                    Toast.makeText(
                        this@PlayerActivity,
                        "错误，开始时间不能再结束时间之后",
                        Toast.LENGTH_SHORT
                    ).show()
                    return false
                }
                stopRecord()
                viewModel.stopRecord(videoInfo, recordStartPos, exoPlayer.currentPosition)
                return true
            }

        })


        // 初始化播放器（但不立即播放）
        with(binding.playerView) {
            this.player = exoPlayer
            useController = true

            setControllerVisibilityListener {
                TAG debug "Controller Visibility: $it: $isControllerVisible"
            }
        }

        exoPlayer.addListener(object : Player.Listener {
            override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
                super.onMediaItemTransition(mediaItem, reason)
                isFirstReady = true
            }

            override fun onPlaybackStateChanged(playbackState: Int) {
                super.onPlaybackStateChanged(playbackState)
                if (playbackState == Player.STATE_ENDED) {
                    // 播放结束了
                    Log.d("ExoPlayer", "Playback ended")
                    viewModel.resetRecord(videoInfo!!)
                    // 你可以在这里做跳转、重播、弹窗等处理
                    if (::endContainer.isInitialized) {
                        btnReplay.setOnClickListener {
                            initVideo()
                            endContainer.visibility = View.GONE
                        }
                        val index = videos!!.indexOf(videoInfo)
                        if (!videos.isNullOrEmpty()) {
                            if (preference.isAutoPlayNextVideo) {
                                if (index != videos!!.lastIndex) {
                                    handler.postDelayed({
                                        endContainer.visibility = View.GONE
                                        videoInfo = videos!![index + 1]
                                        initVideo()
                                    }, 1000)

                                } else {
                                    endContainer.visibility = View.VISIBLE
                                    btnNextVideo.visibility = View.GONE
                                    if (index > 0) {
                                        btnPreVideo.visibility = View.VISIBLE
                                        Glide.with(this@PlayerActivity)
                                            .load(videos!![index - 1].path)
                                            .frame(0)
                                            .into(ivPreVideo)
                                        tvPreVideo.text = videos!![index - 1].nameWithoutExension

                                        btnPreVideo.setOnClickListener {
                                            videoInfo = videos!![index - 1]
                                            initVideo()
                                            endContainer.visibility = View.GONE
                                        }
                                    }
                                }
                            } else {
                                endContainer.visibility = View.VISIBLE

                                if (index > 0) {
                                    btnPreVideo.visibility = View.VISIBLE
                                    Glide.with(this@PlayerActivity)
                                        .load(videos!![index - 1].path)
                                        .frame(0)
                                        .into(ivPreVideo)
                                    tvPreVideo.text = videos!![index - 1].nameWithoutExension

                                    btnPreVideo.setOnClickListener {
                                        videoInfo = videos!![index - 1]
                                        initVideo()
                                        endContainer.visibility = View.GONE
                                    }
                                } else {
                                    btnPreVideo.visibility = View.GONE
                                }
                                if (index < videos!!.lastIndex) {
                                    btnNextVideo.visibility = View.VISIBLE
                                    Glide.with(this@PlayerActivity)
                                        .load(videos!![index + 1].path)
                                        .frame(0)
                                        .into(ivNextVideo)
                                    tvNextVideo.text = videos!![index + 1].nameWithoutExension
                                    btnNextVideo.setOnClickListener {
                                        videoInfo = videos!![index + 1]
                                        initVideo()
                                        endContainer.visibility = View.GONE
                                    }
                                } else {
                                    btnNextVideo.visibility = View.GONE
                                }
                            }
                        }
                    }
                }
                if (playbackState == Player.STATE_READY && isFirstReady) {
                    isFirstReady = false
                    TAG debug "State: STATE_READY"
                    uploadTrace(1)
                    viewModel.loadPlayList(videoInfo!!)
                    handler.post(wakeRunnable)
                    soundTracks = getAvailableAudioTracks(exoPlayer)
                    if (soundTracks.isNullOrEmpty() || soundTracks!!.size == 1) {
                        btnSoundTrackSelector.visibility = View.GONE
                    } else {
                        btnSoundTrackSelector.visibility = View.VISIBLE
                    }
                    subtitleOptions = getSubtitleOptions()
                    if (lastPosition > 0){
                        TAG debug "SeekTo $lastPosition"
                        exoPlayer.seekTo(lastPosition)
                    }
                }


            }

            override fun onPositionDiscontinuity(reason: Int) {
                val curPos = exoPlayer.currentPosition
            }


            override fun onVideoSizeChanged(videoSize: VideoSize) {
                TAG debug "VideoSize from player: ${videoSize.width}x${videoSize.height}"
//                binding.btnMore.visibility = View.VISIBLE
                if (videoSize.width > 0 && videoSize.height > 0) {
                    videoAspectRatio = videoSize.width.toFloat() / videoSize.height.toFloat()
                }
            }
        })


//        if (Preference.getInstance().isMovieMode && !this@PlayerActivity.isTablet()) {
//            toggleRotateScreen()
//        }

        viewModel.playlist.observe(this) {
            this.videos = it
        }

        viewModel.note.observe(this) {
            it?.let {
                noteFile = it
                mediaDir = File(it!!.folder, "html/media")
                if (mediaDir.exists().not()) {
                    mediaDir.mkdirs()
                }
            }
        }

        screenShotLauncher =
            registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
                if (it.resultCode == Activity.RESULT_OK) {
                    val imagePath = it.data?.getStringExtra("image")
                    imagePath?.let {
                        handler.postDelayed({
                            addImage(it)
                        }, 100)
                    }
                }
            }
    }

    private fun initVideo() {
        if (lastPosition == 0L) {
            viewModel.readPlayRecord(videoInfo!!)
        }
        viewModel.getNoteFile(videoInfo!!)
        val dir = File(videoInfo!!.parent)
        val srtFile = dir.listFiles()
            ?.filter { it.extension in listOf("srt", "vtt", "ass") }
            ?.singleOrNull { it.nameWithoutExtension.contains(File(videoInfo!!.path).nameWithoutExtension) }
        srtFile?.let {
            subtitleFilename = srtFile.absolutePath
        }

        if (::titleView.isInitialized) {
            titleView.text = videoInfo!!.nameWithoutExension
        }

        hasSubtitle = !subtitleFilename.isNullOrEmpty()
        viewModel.readPlayRecord(videoInfo!!)
        viewModel.getNoteFile(videoInfo!!)

        preference.lastPlay = videoInfo
        setVideo()
    }

    private fun addImage(tempImagePath: String) {
        PopupDialog.showDialogImageAdd(
            videoInfo!!,
            tempImagePath,
            exoPlayer.currentPosition,
            onConfirm = { name ->
                val srcFile = File(tempImagePath)
                val destFile = File(mediaDir, srcFile.name)
                copyFile(srcFile, destFile, true)
                val syntax = "![${name}](media/${destFile.name})"
                writeToNoteTile(syntax)
                notePanel.show()
                exoPlayer.play()
            },
            onCancel = {
                val file = File(tempImagePath)
                if (file.exists()) {
                    file.delete()
                }
                notePanel.show()
                exoPlayer.play()
            })
    }

    private fun addVideo(videoFile: File, name: String) {
        val syntax = "v{$name}[videos/${videoFile.name}]"
        writeToNoteTile(syntax)
    }

    fun getAvailableAudioTracks(player: ExoPlayer): List<TrackSelectionOption> {
        val options = mutableListOf<TrackSelectionOption>()

        val trackSelector = player.trackSelector as? DefaultTrackSelector ?: return options
        val mappedTrackInfo = trackSelector.currentMappedTrackInfo ?: return options

        for (rendererIndex in 0 until mappedTrackInfo.rendererCount) {
            val trackGroups = mappedTrackInfo.getTrackGroups(rendererIndex)

            val type = player.getRendererType(rendererIndex)
            if (type == C.TRACK_TYPE_AUDIO) {
                for (groupIndex in 0 until trackGroups.length) {
                    val group = trackGroups[groupIndex]
                    for (trackIndex in 0 until group.length) {
                        val format = group.getFormat(trackIndex)
                        options.add(
                            TrackSelectionOption(
                                rendererIndex,
                                groupIndex,
                                trackIndex,
                                format.language ?: "und",
                                format.label ?: "Track ${trackIndex + 1}"
                            )
                        )
                    }
                }
            }
        }

        return options
    }

    private fun initEyeTrace() {
        EYE debug "${preference.enableEyeTrace}"
        if (preference.enableEyeTrace) {
            gazeTrackingController =
                GazeTrackingController(
                    this,
                    this,
                    CameraSelector.DEFAULT_FRONT_CAMERA,
                    1000L
                ) { isFacing ->
                    if (exoPlayer.isPlaying) {
                        if (isFacing != hasEyeOn) {
                            uploadTrace(0)
                        }
                    }

                    this.hasEyeOn = isFacing


                    EYE debug "isFacing:$isFacing"
                    if (!isPaused) {
                        if (!isFacing) {
                            exoPlayer.pause()
                            isPaused = true
                        }
                    } else {
                        if (isFacing) {
                            isPaused = false
                            exoPlayer.play()
                        }
                    }
                }
            gazeTrackingController?.start()
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    private fun initUi() {
        btnSubtitle = binding.playerView.findViewById(R.id.btn_subtitle)
        updateBtnSustitle()

        btnSubtitle.setOnClickListener {
            if (hasSubtitle) {
                showSubtitle = !showSubtitle
                toggleSubtitle(showSubtitle)
                btnSubtitle.setImageResource(if (showSubtitle) R.drawable.baseline_subtitles_24 else R.drawable.baseline_subtitles_off_24)
            }
        }
        TAG debug videoInfo!!.gson()
        titleView = binding.playerView.findViewById(R.id.video_title)
        titleView.text = videoInfo!!.nameWithoutExension

        btnBack = binding.playerView.findViewById<ImageView>(R.id.btn_back)
        btnBack.setOnClickListener {
            exoPlayer.stop()
            exoPlayer.release()
            this@PlayerActivity.finish()
        }

        btnSoundTrackSelector = binding.playerView.findViewById(R.id.btn_audio_track)
        btnSoundTrackSelector.visibility = View.GONE
        btnSoundTrackSelector.setOnClickListener {
            if (!soundTracks.isNullOrEmpty()) {
                showSoundTraceSelecDialog(soundTracks!!)
            }
        }

        btnSubtitleSelector = binding.playerView.findViewById(R.id.btn_subtitle_trace)
        btnSubtitleSelector.setOnClickListener {

        }

        btnRotate = binding.playerView.findViewById<ImageView>(R.id.btn_full_screen)
        isLandscape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
        btnRotate.setOnClickListener {
            toggleRotateScreen()
        }

        btnLock = binding.playerView.findViewById<ImageView>(R.id.btn_lock)
        if (!isLandscape) {
            btnLock.visibility = View.GONE
        } else {
            btnLock.visibility = View.VISIBLE
        }
        btnLock.setOnClickListener {
            isLocked = true
            binding.playerView.hideController()
            binding.btnUnlock.visibility = View.VISIBLE
            binding.clickOverlay.visibility = View.VISIBLE
            handler.removeCallbacksAndMessages(null)
            handler.postDelayed({ binding.btnUnlock.visibility = View.GONE }, 3000L)
        }


        btnPlayList = binding.playerView.findViewById<ImageView>(R.id.btn_list)
        btnPlayList.setOnClickListener {
            if (!videos.isNullOrEmpty()) {
                PopupDialog.showPlaylist(videoInfo!!, videos!!, onPlay = {
                    TAG debug "Select new Video:${it.nameWithoutExension}"
                    videoInfo = it
                    initVideo()
                }, dismiss = {})

            }
        }

        btnZoom = binding.playerView.findViewById(R.id.btn_zoom)
        btnZoom.setOnClickListener {
            isZoomMode = true
            if (isZoomMode) {
                binding.playerView.hideController()
                Toast.makeText(
                    this@PlayerActivity,
                    "用两个手指控制要缩放的范围",
                    Toast.LENGTH_SHORT
                ).show()
                binding.btnCloseZoom.visibility = View.VISIBLE
            }
        }

        binding.btnCloseZoom.setOnClickListener {
            isZoomMode = false
            binding.btnCloseZoom.visibility = View.GONE
            currentScale = 1.0f
            translateX = 0f
            translateY = 0f
            binding.playerView.videoSurfaceView?.apply {
                pivotX = width / 2f
                pivotY = height / 2f
                scaleX = 1f
                scaleY = 1f
                translationX = 0f
                translationY = 0f
            }
        }

        btnResize = binding.playerView.findViewById<ImageView>(R.id.btn_scale)
        btnResize.setOnClickListener {
            resizeMode++
            resizeMode %= 3
            setDisplayMode(resizeMode)
        }

        btnSpeed = binding.playerView.findViewById<ImageView>(R.id.btn_speed)
        btnSpeed.setOnClickListener {
            adjustPlaySpeed()
        }

        timeBar = binding.playerView.findViewById<DefaultTimeBar>(R.id.exo_progress)
        timeBar.addListener(object : TimeBar.OnScrubListener {
            override fun onScrubStart(timeBar: TimeBar, position: Long) {
                binding.tvProgress.visibility = View.VISIBLE
                binding.tvProgress.text = exoPlayer.currentPosition.formatMillsecond()
            }

            override fun onScrubMove(timeBar: TimeBar, position: Long) {
                binding.tvProgress.text = position.formatMillsecond()
            }

            override fun onScrubStop(timeBar: TimeBar, position: Long, canceled: Boolean) {
                handler.removeCallbacksAndMessages(null)
                handler.postDelayed({ binding.tvProgress.visibility = View.GONE }, 2000L)
            }
        })

        binding.clickOverlay.setOnClickListener {
            TAG debug "ClickOverlay: clicked!: isBtnUnlockVisible:${binding.btnUnlock.visibility == View.VISIBLE}"
            binding.btnUnlock.visibility = View.VISIBLE
            handler.removeCallbacksAndMessages(null)
            handler.postDelayed({ binding.btnUnlock.visibility = View.GONE }, 3000L)
        }

        binding.btnUnlock.setOnClickListener {
            binding.btnUnlock.visibility = View.GONE
            isLocked = false
            binding.playerView.showController()
            binding.clickOverlay.visibility = View.GONE
        }

        binding.playerView.setOnTouchListener { _, event ->
            when (event.actionMasked) {  // 使用actionMasked而不是action来处理多指手势
                MotionEvent.ACTION_DOWN -> {
                    initialX = event.x
                    initialY = event.y
                    initialTouchTime = System.currentTimeMillis()
                    isLeftSide = initialX < binding.playerView.width / 2
                    isScrolling = false
                    lastDragX = event.x
                    lastDragY = event.y
                    false
                }

                MotionEvent.ACTION_POINTER_DOWN -> {
                    if (event.pointerCount == 2 && isZoomMode) {
                        // 计算两指中心点作为缩放原点
                        pivotX = (event.getX(0) + event.getX(1)) / 2
                        pivotY = (event.getY(0) + event.getY(1)) / 2

                        // 转换为相对于PlayerView的坐标
                        val location = IntArray(2)
                        binding.playerView.getLocationOnScreen(location)
                        pivotX -= location[0]
                        pivotY -= location[1]

                        initialTouchDistance = getFingerDistance(event)
                        initialScale = currentScale
                        isScrolling = true
                    }
                    true
                }

                MotionEvent.ACTION_MOVE -> {
                    if (event.pointerCount == 2 && isZoomMode) {
                        // 计算新的两指中心点（实时更新）
                        val newPivotX = (event.getX(0) + event.getX(1)) / 2
                        val newPivotY = (event.getY(0) + event.getY(1)) / 2

                        // 计算缩放比例
                        val newDistance = getFingerDistance(event)
                        val scale = (newDistance / initialTouchDistance) * initialScale
                        currentScale = scale.coerceIn(minScale, maxScale)

                        // 应用缩放（带中心点）
                        applyZoomWithPivot(currentScale, newPivotX, newPivotY)

                        return@setOnTouchListener true
                    } else if (event.pointerCount == 1 && isZoomMode && currentScale > 1f) {
                        // 拖动画面内容
                        val dx = event.x - lastDragX
                        val dy = event.y - lastDragY
                        translateX += dx
                        translateY += dy

                        val videoWidth = binding.playerView.width.toFloat()
                        val videoHeight = binding.playerView.height.toFloat()

                        val maxTranslateX = (videoWidth * (currentScale - 1)) / 2
                        val maxTranslateY = (videoHeight * (currentScale - 1)) / 2

                        translateX = translateX.coerceIn(-maxTranslateX, maxTranslateX)
                        translateY = translateY.coerceIn(-maxTranslateY, maxTranslateY)

                        applyTranslationWithPivot(translateX, translateY)
                        lastDragX = event.x
                        lastDragY = event.y

                        return@setOnTouchListener true
                    } else if (event.pointerCount == 1 ) {
                        val deltaX = event.x - initialX
                        val deltaY = event.y - initialY

                        if (!isScrolling) {
                            if (abs(deltaX) > touchSlop || abs(deltaY) > touchSlop) {
                                isScrolling = true

                                scrollDirection = if (abs(deltaY) > abs(deltaX)) {
                                    if (isLeftSide) ScrollDirection.VERTICAL_LEFT else ScrollDirection.VERTICAL_RIGHT
                                } else {
                                    ScrollDirection.HORIZONTAL
                                }
                            }
                        }

                        // 方向已确定，持续处理
                        if (isScrolling) {
                            val dx = event.x - lastDragX
                            val dy = event.y - lastDragY

                            accumulatedX += dx
                            accumulatedY += dy

                            when (scrollDirection) {
                                ScrollDirection.VERTICAL_LEFT -> {
                                    if (abs(accumulatedY) >= adjustmentThreshold) {
                                        val percent = (accumulatedY / binding.playerView.height).coerceIn(-1f, 1f) * 0.5f
                                        setActivityBrightness(-percent)
                                        accumulatedY = 0f
                                    }
                                }

                                ScrollDirection.VERTICAL_RIGHT -> {
                                    if (abs(accumulatedY) >= adjustmentThreshold) {
                                        val percent = (accumulatedY / binding.playerView.height).coerceIn(-1f, 1f) * 0.5f
                                        adjustVolume(-percent)
                                        accumulatedY = 0f
                                    }
                                }

                                ScrollDirection.HORIZONTAL -> {
                                    if (abs(accumulatedX) >= adjustmentThreshold) {
                                        val percent = (accumulatedX / binding.playerView.width).coerceIn(-1f, 1f)
                                        seekToRelative(percent)
                                        accumulatedX = 0f
                                    }
                                }

                                else -> {}
                            }

                            lastDragX = event.x
                            lastDragY = event.y

                            return@setOnTouchListener true
                        }
                    }
                    false
                }

                MotionEvent.ACTION_POINTER_UP -> {  // 处理多指抬起
                    if (event.pointerCount == 2) {
                        isScrolling = false  // 重置滚动状态
                    }
                    true
                }

                MotionEvent.ACTION_UP -> {
                    if (!isScrolling) {
                        val deltaX = event.x - initialX
                        val deltaY = event.y - initialY
                        val maxTapDistance = 20  // 允许最大偏移像素，可调节
                        if (abs(deltaX) < maxTapDistance && abs(deltaY) < maxTapDistance) {
                            toggleControllerVisibility()
                        }
                    }
                    isScrolling = false
                    true
                }

                else -> false
            }
        }

        btnNote = binding.playerView.findViewById(R.id.btn_note)
        btnNote.setOnClickListener {
            if (noteFile == null) {
                val dialog = AlertDialog.Builder(this@PlayerActivity)
                    .setMessage("是否为这个视频创建Markdown笔记?")
                    .setPositiveButton(R.string.confirm) { _, _ ->
                        createNote(videoInfo!!)
                        showNotePanel()
                    }
                    .setNegativeButton(R.string.cancel, null)
                dialog.setOnDismissListener {
                    setImmersiveMode()
                }
                dialog.show()
            } else {
                showNotePanel()
            }
        }

        endContainer = binding.playerView.findViewById(R.id.end_contaienr)
        endContainer.visibility = View.GONE
        btnReplay = binding.playerView.findViewById(R.id.btn_replay)
        btnPreVideo = binding.playerView.findViewById(R.id.btn_pre_video)
        btnNextVideo = binding.playerView.findViewById(R.id.btn_next_video)
        ivNextVideo = binding.playerView.findViewById(R.id.iv_next_video)
        ivPreVideo = binding.playerView.findViewById(R.id.iv_prev_video)

        tvPreVideo = binding.playerView.findViewById(R.id.tv_pre_video)
        tvNextVideo = binding.playerView.findViewById(R.id.tv_next_video)


    }

    private fun seekToRelative(percent: Float) {
        val player = exoPlayer ?: return
        val duration = player.duration
        if (duration <= 0) return
        val seekOffset = (duration * percent * 0.01).toLong()
        var newPosition = player.currentPosition + seekOffset
        SCROLL debug "Seek: percent:$percent offset: $seekOffset newPos: ${newPosition.formatPosition()} "
        newPosition = newPosition.coerceIn(0L, duration)
        player.seekTo(newPosition)

        // 可选：显示一个 UI 反馈，如“快进 10 秒”之类
        binding.tvProgress.text = newPosition.formatPosition()
        binding.tvProgress.visibility = View.VISIBLE
        handler.removeCallbacksAndMessages(null)
        handler.postDelayed({binding.tvProgress.visibility = View.GONE},  2000L)
    }

    private fun stopRecord() {
        isRecording = false
        notePanel.stopRecord()
    }

    private fun writeToNoteTile(text: String) {
        viewModel.writeToNote(text)
    }

    private fun showNotePanel() {
        if (notePanel.isShowing.not()) {
            notePanel.show()
        }
    }

    private fun createNote(videoInfo: VideoFileInfo) {
        viewModel.createNote(videoInfo)
    }

    private fun showSoundTraceSelecDialog(soundTracks: List<TrackSelectionOption>) {
        PopupDialog.showSoundTrackSelectDialog(soundTracks, this.selectedSoundTrack) { track, pos ->
            selectAudioTrack(track)
            this.selectedSoundTrack = pos
        }
    }

    fun selectAudioTrack(option: TrackSelectionOption) {
        val trackSelector = exoPlayer.trackSelector as? DefaultTrackSelector ?: return
        val mappedTrackInfo = trackSelector.currentMappedTrackInfo ?: return

        val trackGroups = mappedTrackInfo.getTrackGroups(option.rendererIndex)
        if (option.groupIndex >= trackGroups.length) return
        val group = trackGroups[option.groupIndex]

        val override = DefaultTrackSelector.SelectionOverride(option.groupIndex, option.trackIndex)

        val parameters = trackSelector.parameters
            .buildUpon()
            .setRendererDisabled(option.rendererIndex, false)
            .setSelectionOverride(option.rendererIndex, trackGroups, override)
            .build()

        trackSelector.setParameters(parameters)
    }

    private fun applyZoomWithPivot(scale: Float, pivotX: Float, pivotY: Float) {
        // 方法1：使用Transform API（推荐）
        binding.playerView.videoSurfaceView?.apply {
            this.pivotX = pivotX
            this.pivotY = pivotY
            this.scaleX = scale
            this.scaleY = scale
        }
    }

    private fun applyTranslationWithPivot(translationX: Float, translationY: Float) {

        binding.playerView.videoSurfaceView?.apply {
            this.translationX = translationX
            this.translationY = translationY
        }
    }

    /**
     * 计算两个触摸点之间的直线距离
     * @param event 触摸事件对象
     * @return 两指之间的像素距离
     */
    private fun getFingerDistance(event: MotionEvent): Float {
        // 确保至少有两个触摸点
        if (event.pointerCount < 2) return 0f

        // 获取第一个手指的坐标
        val x1 = event.getX(0)
        val y1 = event.getY(0)

        // 获取第二个手指的坐标
        val x2 = event.getX(1)
        val y2 = event.getY(1)

        // 计算两点之间的直线距离（勾股定理）
        val dx = x1 - x2
        val dy = y1 - y2
        return sqrt(dx * dx + dy * dy)
    }

    private fun applyAspectRatioScale(scale: Float) {
        val clampedScale = scale.coerceIn(minScale, maxScale)
        binding.playerView.videoSurfaceView?.apply {
            scaleX = clampedScale
            scaleY = clampedScale
            pivotX = width / 2f
            pivotY = height / 2f
        }
    }

    private fun updateBtnSustitle() {
        if (!hasSubtitle) {
            btnSubtitle.setImageResource(R.drawable.baseline_subtitles_off_24)
        } else {
            btnSubtitle.setImageResource(R.drawable.baseline_subtitles_24)
            binding.playerView.subtitleView?.background =
                ContextCompat.getDrawable(this, R.drawable.subtitle_bg)
        }
    }

    private fun updateAudioButton() {
        if (preference.enableAudioMode) {
            btnAudio.setImageResource(R.drawable.ic_audio_w)
        } else {
            btnAudio.setImageResource(R.drawable.ic_audio_g)
        }
    }


    override fun onPause() {
        super.onPause()
        uploadTrace(2)
    }

    override fun onRestart() {
        super.onRestart()
        if (isPaused) {
            isPaused = false
            exoPlayer.play()
            uploadTrace(3)
        }
    }

    private fun adjustVolume(percent: Float) {
        val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
        val maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
        val currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)

        // 更精细的音量控制
        val delta = (percent * maxVolume * 8f).toInt()
        val newVolume = (currentVolume + delta).coerceIn(0, maxVolume)
        VOL debug "percent:$percent/delta:$delta/newVolume:$newVolume"
        audioManager.setStreamVolume(
            AudioManager.STREAM_MUSIC,
            newVolume,
            AudioManager.FLAG_SHOW_UI
        )

        showSettingFeedback(
            iconRes = R.drawable.baseline_volume_up_24,
            text = "$newVolume/$maxVolume"
        )
    }

    private fun showSettingFeedback(iconRes: Int, text: String) {
        binding.settingContainer.visibility = View.VISIBLE
        binding.ivSetting.setImageResource(iconRes)
        binding.tvSetting.text = text

        handler.removeCallbacksAndMessages(null)
        handler.postDelayed(
            { binding.settingContainer.visibility = View.GONE },
            1000L
        )
    }

    private fun toggleControllerVisibility() {
        if (binding.playerView.isControllerVisible) {
            binding.playerView.hideController()
        } else {
            binding.playerView.showController()
        }
    }

    private fun adjustPlaySpeed() {
        val curSpeed = exoPlayer.playbackParameters.speed
        PopupDialog.showSpeedDialog(curSpeed, btnSpeed) { newSpeed ->
            exoPlayer.setPlaybackSpeed(newSpeed)
        }
    }


    private fun setVideo() {
        exoPlayer.stop()
        exoPlayer.clearMediaItems()

        val dataSourceFactory = DefaultDataSource.Factory(this)
        val videoUri = Uri.fromFile(File(videoInfo!!.path))
        val videoSource = ProgressiveMediaSource.Factory(dataSourceFactory)
            .createMediaSource(MediaItem.fromUri(videoUri))

        if (!subtitleFilename.isNullOrEmpty()) {
            val subtitleFile = File(subtitleFilename!!)
            if (subtitleFile.exists()) {
                val subtitleUri = Uri.fromFile(subtitleFile)
                val subtitle = MediaItem.Subtitle(
                    subtitleUri,
                    MimeTypes.APPLICATION_SUBRIP,
                    "und",
                    C.SELECTION_FLAG_DEFAULT
                )
                val subtitleSource = SingleSampleMediaSource.Factory(dataSourceFactory)
                    .createMediaSource(subtitle, C.TIME_UNSET)
                val mergedSource = MergingMediaSource(videoSource, subtitleSource)
                exoPlayer.setMediaSource(mergedSource)
                if (::btnSubtitle.isInitialized) {
                    btnSubtitle.visibility = View.VISIBLE
                }
            } else {
                Log.w("Player", "字幕文件不存在：$subtitleFilename")
                if (::btnSubtitle.isInitialized) {
                    btnSubtitle.visibility = View.GONE
                }
                exoPlayer.setMediaSource(videoSource)
            }
        } else {
            exoPlayer.setMediaSource(videoSource)
        }
        exoPlayer.prepare() // ⚠️你之前没调用这句
//        if (lastPosition > 0){
//            exoPlayer.seekTo(lastPosition)
//        }
    }


    private fun adjustVideoContainerHeight(isLandScape: Boolean) {
        // 如果是横屏模式，container
        if (isLandScape) {
            binding.videoContainer.layoutParams = binding.videoContainer.layoutParams.apply {
                width = realScreenWidth
                height = realScreenHeight
            }
            binding.videoContainer.requestLayout()
            return
        } else {

            if (videoSize == null) {
                Log.w(TAG, "视频分辨率未知，无法调整高度")
                return
            }
            val videoWidth = videoSize!!.first
            val videoHeight = videoSize!!.second

            if (videoWidth <= 0 || videoHeight <= 0) return

            binding.videoContainer.layoutParams = binding.videoContainer.layoutParams.apply {
                height =
                    if (preIsShowNoteContainer) portraitVideoContainerHeight else realScreenWidth
                width = realScreenHeight
            }
            binding.videoContainer.requestLayout()
        }
    }

    fun getVideoSize(path: String): Pair<Int, Int>? {
        val retriever = MediaMetadataRetriever()
        return try {
            retriever.setDataSource(path)
            val width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)
                ?.toIntOrNull()
            val height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)
                ?.toIntOrNull()
            if (width != null && height != null) Pair(width, height) else null
        } catch (e: Exception) {
            Log.e(TAG, "获取视频分辨率失败", e)
            null
        } finally {
            retriever.release()
        }
    }

    private fun toggleRotateScreen() {
        isLandscape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
        if (!isLandscape) {
            TransitionManager.beginDelayedTransition(binding.container)
            binding.noteContainer.visibility = View.GONE
            handler.postDelayed({
                requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE

                binding.playerView.useController = true // 显示控制器
            }, 200L)
        } else {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT

            binding.playerView.useController = true // 隐藏控制器
        }
//        val newLandScape = !isLandscape

        // 旋转屏幕后重新调整视频高度（宽高比变了，宽度还是屏幕宽度）
        // 注意：横屏时视频高度通常小于竖屏，所以这里以屏幕宽度适配
//        adjustVideoContainerHeight(newLandScape)
    }

    override fun onResume() {
        super.onResume()
        // 延迟播放，保证 UI 初始化完成后开始
        setImmersiveMode()
        isLandscape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
//        adjustPlayerViewHeight(isLandscape)
        if (!exoPlayer.isPlaying) {
            exoPlayer.prepare()
            exoPlayer.seekTo(lastPosition)
            exoPlayer.play()
        }

        PopupDialog.onDismiss = {

        }
        PopupDialog.onDismiss = {
            setImmersiveMode()
        }
    }

    override fun onStop() {
        super.onStop()
        TAG debug "onStop"
        if (!preference.enableAudioMode) {
            viewModel.updatePlayRecord(exoPlayer.currentPosition)
            exoPlayer.pause()
            isPaused = true
        }
        uploadTrace(2)
        handler.removeCallbacksAndMessages(wakeRunnable)
        window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
    }

    override fun onDestroy() {
        super.onDestroy()
        TAG debug "OnDestroy"
        viewModel.updatePlayRecord(exoPlayer.currentPosition)
        exoPlayer.release()
        gazeTrackingController?.stop()
        uploadTrace(4)
        conn?.let {
            unbindService(it)
        }
    }

    fun uploadTrace(action: Int) {
        traceService.report(
            EyeReport(
                videoInfo!!.name, action, hasEyeOn
            )
        )
    }

    private fun adjustPlayerViewHeight(isLandScape: Boolean) {

        if (isLandScape) {
            binding.playerView.layoutParams = binding.playerView.layoutParams.apply {
                width = realScreenWidth
                height = realScreenHeight
            }
            binding.playerView.requestLayout()
            return
        } else {
            val videoFormat = exoPlayer.videoFormat
            if (videoFormat == null) {
                Log.w(TAG, "视频信息尚未获取，无法调整高度")
                return
            }

            val videoWidth = videoFormat.width
            val videoHeight = videoFormat.height

            if (videoWidth <= 0 || videoHeight <= 0) return
            val newHeight = (realScreenHeight * (videoHeight.toFloat() / videoWidth)).toInt()

//            binding.playerView.layoutParams = binding.playerView.layoutParams.apply {
//                height = newHeight
//                width = realScreenWidth
//            }
//            binding.playerView.requestLayout()
        }
    }

    fun getRealScreenSize() {
        val result = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            val bounds = windowManager.currentWindowMetrics.bounds
            bounds.width() to bounds.height()
        } else {
            val metrics = Resources.getSystem().displayMetrics
            metrics.widthPixels to metrics.heightPixels
        }
        realScreenWidth = result.first
        realScreenHeight = result.second
        TAG debug "RealResolution: width:$realScreenWidth/height:$realScreenHeight"
    }

    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        setImmersiveMode()  // 重新进入沉浸模式
        TAG debug "isLandScape:$isLandscape"


    }

    fun setImmersiveMode() {
        WindowCompat.setDecorFitsSystemWindows(window, false)
        val controller = WindowInsetsControllerCompat(window, window.decorView)
        controller.hide(WindowInsetsCompat.Type.systemBars())
        controller.systemBarsBehavior =
            WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
    }

    fun setActivityBrightness(percent: Float) {

        val lp = window.attributes

        // 读取当前亮度
        val current = if (lp.screenBrightness < 0) {
            val resolver = contentResolver
            try {
                val sysBrightness =
                    Settings.System.getInt(resolver, Settings.System.SCREEN_BRIGHTNESS)
                val normalized = sysBrightness / 255f
                Log.d("Brightness", "System brightness = $sysBrightness, normalized = $normalized")
                normalized
            } catch (e: Exception) {
                Log.e("Brightness", "Error getting system brightness", e)
                0.5f
            }
        } else {
            Log.d("Brightness", "Window brightness (custom) = ${lp.screenBrightness}")
            lp.screenBrightness
        }

        // 计算新亮度
        val delta = percent * 1f
        val newBrightness = (current + delta).coerceIn(0.01f, 1f)
        Log.d("Brightness", "percent = $percent, delta = $delta, newBrightness = $newBrightness")

        lp.screenBrightness = newBrightness
        window.attributes = lp

        // 反馈显示
        showSettingFeedback(
            iconRes = R.drawable.baseline_brightness_medium_24,
            text = "${(newBrightness * 100).toInt()}%"
        )
    }


    fun setDisplayMode(mode: Int) {
        binding.playerView.resizeMode = when (mode) {
            0 -> AspectRatioFrameLayout.RESIZE_MODE_FILL
            1 -> AspectRatioFrameLayout.RESIZE_MODE_FIT
            else -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM
        }
    }

    fun toggleSubtitle(show: Boolean) {
        binding.playerView.subtitleView?.visibility = if (show) View.VISIBLE else View.GONE
    }

    fun selectSubtitle(index: Int) {
        val mappedTrackInfo = trackSelector.currentMappedTrackInfo ?: return

        for (i in 0 until mappedTrackInfo.rendererCount) {
            val trackGroups = mappedTrackInfo.getTrackGroups(i)
            if (trackGroups.length == 0) continue

            val trackType = exoPlayer.getRendererType(i)
            if (trackType == C.TRACK_TYPE_TEXT) {
                val parametersBuilder = trackSelector.buildUponParameters()
                if (index == -1) {
                    // 关闭字幕
                    parametersBuilder.clearSelectionOverrides(i)
                    parametersBuilder.setRendererDisabled(i, true)
                } else {
                    val override = DefaultTrackSelector.SelectionOverride(index, 0)
                    parametersBuilder.setSelectionOverride(i, trackGroups, override)
                    parametersBuilder.setRendererDisabled(i, false)
                }
                trackSelector.parameters = parametersBuilder.build()
                break
            }
        }
    }

    override fun onScale(p0: ScaleGestureDetector): Boolean {
        return false
    }

    override fun onScaleBegin(p0: ScaleGestureDetector): Boolean {
        return false
    }

    override fun onScaleEnd(p0: ScaleGestureDetector) {

    }


    fun getSubtitleOptions(): List<SubtitleOption> {
        val trackSelector = exoPlayer.trackSelector as? DefaultTrackSelector ?: return emptyList()
        val mappedTrackInfo = trackSelector.currentMappedTrackInfo ?: return emptyList()

        val options = mutableListOf<SubtitleOption>()

        for (i in 0 until mappedTrackInfo.rendererCount) {
            if (exoPlayer.getRendererType(i) != C.TRACK_TYPE_TEXT) continue

            val groups = mappedTrackInfo.getTrackGroups(i)
            for (groupIndex in 0 until groups.length) {
                val group = groups[groupIndex]
                for (trackIndex in 0 until group.length) {
                    val format = group.getFormat(trackIndex)
                    val language = format.language ?: "und"
                    val label = format.label ?: when {
                        format.selectionFlags and C.SELECTION_FLAG_DEFAULT != 0 -> "外挂字幕"
                        else -> "字幕 ${trackIndex + 1}"
                    }
                    options.add(SubtitleOption(i, groupIndex, trackIndex, language, label))
                }
            }
        }

        return options
    }

}
enum class ScrollDirection { NONE, HORIZONTAL, VERTICAL_LEFT, VERTICAL_RIGHT }